package com.ihr360.payroll.service.salarytasklet.step.reader;

import com.google.common.collect.Lists;
import com.ihr360.alps.api.ServiceProvider;
import com.ihr360.common.DateRange;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.expr.engine.DependencyEngine;
import com.ihr360.job.core.annotation.BeforeRead;
import com.ihr360.job.core.item.ItemReader;
import com.ihr360.job.core.item.NonTransientResourceException;
import com.ihr360.job.core.item.ParseException;
import com.ihr360.job.core.item.UnexpectedInputException;
import com.ihr360.job.core.repository.JobRepository;
import com.ihr360.job.core.scope.context.SimpleStepContext;
import com.ihr360.payroll.calc.StaffSalaryCalcPeriod;
import com.ihr360.payroll.service.salarytasklet.SalaryReferenceDataService;
import com.ihr360.payroll.service.salarytasklet.step.SalaryCalcContext;
import com.ihr360.shared.basicstaffinfo.dao.SyncedStaffInfoRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 根据员工薪资档案获取分段信息
 */
/**
 * @author davidwei
 */
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class CombineSalaryCalcBasedInfoReader implements ItemReader<Map<String, StaffSalaryCalcPeriod>> {
    private static final int CHUNK_SIZE = 50;

    final Logger logger = LoggerFactory.getLogger(DependencyEngine.class.getName());
    SimpleStepContext simpleStepContext;

    @Autowired
    JobRepository jobRepository;

    @Autowired
    SyncedStaffInfoRepository syncedStaffInfoRepository;


    @Autowired
    private SalaryReferenceDataService salaryReferenceDataService;


    private SalaryCalcContext salaryCalcContext;

    private DateRange payrollPeriodRange;

    private DateRange attendancePeriodRange;

    private boolean isSamePeriod;

    private List<List<String>> partitions;

    private int cursor = 0;

    private int partionSize = 0;

    public void setSalaryCalcContext(SalaryCalcContext salaryCalcContext) {
        this.salaryCalcContext = salaryCalcContext;
    }

    public void setPeriodRanges(DateRange payrollPeriodRange, DateRange attendancePeriodRange) {
        this.payrollPeriodRange = payrollPeriodRange;
        this.attendancePeriodRange = attendancePeriodRange;
    }

    @Override
    public Map<String, StaffSalaryCalcPeriod> read() throws Exception, ParseException, NonTransientResourceException {
        if (cursor == 0) {
            List<? extends String> staffs = this.salaryCalcContext.salaryPlanStaffListItemWriter.getWrittenItems();
            List<String> cloneStaffs = new ArrayList<>();
            staffs.stream().forEach(s -> cloneStaffs.add(s));
            this.partitions = Lists.partition(cloneStaffs, CHUNK_SIZE);
            partionSize = this.partitions.size();
        }
        if (cursor >= partionSize) {
            cursor=0;
            return null;
        }
        List<String> subStaffIds = partitions.get(cursor);
        //汇总员工的信息
        Map<String, Set<String>> references = this.salaryCalcContext.dependencyEngineHolder.getWrittenItem().getSalaryReferences();

        //StaffSalaryCalcPeriod 里面包含了薪资计算需要的分段信息，注意 员工基本薪资的分段引用和 考勤的分段可能不同
        Map<String, StaffSalaryCalcPeriod> staffSalaryCalcPeriodMap = salaryReferenceDataService.loadSalaryPeriodsOfStaffs(salaryCalcContext.getCompanyId(), references.get(ServiceProvider.SERVICE_ID.STAFF_SALARY), subStaffIds, payrollPeriodRange, attendancePeriodRange);

        staffSalaryCalcPeriodMap.values().stream().forEach(s -> {
            encloseSalaryCalcPeriod(s, salaryCalcContext.getTermStartOn(), salaryCalcContext.getTermEndOn(), salaryCalcContext.getPayPeriodYear(), salaryCalcContext.getPayPeriodMonth());
        });

        Set<String> staffKeys = staffSalaryCalcPeriodMap.keySet();

        List<String> notExistStaffIds = subStaffIds.stream().filter(s -> !staffKeys.contains(s)).collect(Collectors.toList());


        //获取没有薪资薪资的staff的基本信息
        if (CollectionUtils.isNotEmpty(notExistStaffIds)) {
            String companyId = salaryCalcContext.getCompanyId();
            List<Object[]> staffInfos = syncedStaffInfoRepository.findByCompanyIdAndIdsIn(companyId, notExistStaffIds);
            Map<String, Object> staffIdAndNameMap = staffInfos.stream().collect(Collectors.toMap(s -> s[0].toString(), s -> s[1]));
            for (String staffId : notExistStaffIds) {
                Object name = staffIdAndNameMap.get(staffId);
//                String staffName = name != null ? name.toString() : staffId; staffId超出staffName字段长度
                String staffName = name != null ? name.toString() : null;
                jobRepository.warning(simpleStepContext, "[薪资档案]", String.format("无法获取获取员工(%s)薪资档案信息", name != null ? name.toString() : staffId));
                StaffSalaryCalcPeriod s = new StaffSalaryCalcPeriod(staffId, staffName);
                encloseSalaryCalcPeriod(s, salaryCalcContext.getTermStartOn(), salaryCalcContext.getTermEndOn(), salaryCalcContext.getPayPeriodYear(), salaryCalcContext.getPayPeriodMonth());
                staffSalaryCalcPeriodMap.put(staffId, s);
            }
        }

        cursor++;
        return staffSalaryCalcPeriodMap;
    }

    private void encloseSalaryCalcPeriod(StaffSalaryCalcPeriod salaryCalcPeriod, Date startOn, Date endOn, int year, int month) {
        salaryCalcPeriod.setCompanyId(salaryCalcContext.getCompanyId());
        salaryCalcPeriod.setTermId(salaryCalcContext.getTermId());
        salaryCalcPeriod.setStartOn(startOn);
        salaryCalcPeriod.setEndOn(endOn);
        salaryCalcPeriod.setYear(year);
        salaryCalcPeriod.setMonth(month);
    }

    @BeforeRead
    public void setSimpleStepContext(SimpleStepContext simpleStepContext) {
        this.simpleStepContext = simpleStepContext;
    }

}